package com.heima.comment.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.comment.dtos.CommentRepayDto;
import com.heima.comment.dtos.CommentRepayLikeDto;
import com.heima.comment.dtos.CommentRepayListDto;
import com.heima.comment.pojos.ApComment;
import com.heima.comment.pojos.ApCommentLike;
import com.heima.comment.service.CommentRepayService;
import com.heima.comment.vos.ApCommentVo;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.feign.client.ApUserFeignClient;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.pojos.ApUser;
import com.heima.utils.thread.ApThreadLocalUtil;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.core.query.UpdateDefinition;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author Gareth Cao
 * @date 2022/6/27 21:47
 */
@Service
public class CommentRepayServiceImpl implements CommentRepayService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ApUserFeignClient apUserFeignClient;

    @Autowired
    private MongoTemplate mongoTemplate;
    @Override
    public ResponseResult saveCommentRepay(CommentRepayDto dto) {
        //1 校验参数是否存在
        if (dto.getCommentId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        //2 从本地线程获取用户信息
        ApUser apUser = ApThreadLocalUtil.getUser();
        if (apUser == null) {
            //未登录或者登录过期了
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        if (apUser.getId() == 0) {
            //游客不让进行用户行为操作
            return ResponseResult.errorResult(AppHttpCodeEnum.VISITOR_NEED_LOGIN);
        }
        //3 判断redis中是否有该用户的信息，没有则调用feign接口查询并存储到redis中
        //3.1 定义redis中存储用户信息的key
        String user_key = "LOGIN_USER_" + apUser.getId();
        String apUserStr = stringRedisTemplate.opsForValue().get(user_key);
        if (StringUtils.isEmpty(apUserStr)) {
            //从远程服务调用
            ResponseResult<ApUser> result = apUserFeignClient.findUserById(apUser.getId().longValue());
            if (result.getCode() == 200 && result.getData() != null) {
                //将用户信息存入到redis,并设置2小时的过期时间
                stringRedisTemplate.opsForValue().set(user_key, JSON.toJSONString(apUser), 2, TimeUnit.HOURS);
            }
        } else {
            //redis中有用户的信息，从json字符串中解析出用户数据
            apUser = JSON.parseObject(apUserStr, ApUser.class);
        }
        //4 对评论信息进行审查
        Boolean flag = scanContent(dto.getContent());
        if (!flag) {
            //评论没有审查通过
            return ResponseResult.errorResult(AppHttpCodeEnum.COMMENT_NOT_PASS);
        }
        //审查通过，将数据存入到mongo中
        ApComment apComment = new ApComment();
        apComment.setId(ObjectId.get().toHexString());
        apComment.setUserId(apUser.getId());
        apComment.setNickName(apUser.getName());
        apComment.setImage(apUser.getImage());
        apComment.setTargetId(dto.getCommentId().toString());
        apComment.setContent(dto.getContent());
        apComment.setLikes(0);
        apComment.setReply(0);
        apComment.setCreatedTime(new Date());
        apComment.setUpdatedTime(new Date());
        mongoTemplate.insert(apComment);


        //用来新增评论回复消息时，评论集合中的reply应该加一
        Query query = Query.query(Criteria.where("id").is(dto.getCommentId()));
        UpdateDefinition updateDefinition = new Update().inc("reply", 1);
        mongoTemplate.updateFirst(query,updateDefinition,ApComment.class);

        return ResponseResult.okResult("评论成功");
    }


    @Autowired
    private GreenTextScan greenTextScan;

    /**
     * 抽取的检查评论内容的方法
     *
     * @param content
     * @return
     */
    private Boolean scanContent(String content) {
        //定义返回值
        Boolean flag = true;
        try {
            Map map = greenTextScan.greeTextScan(content);
            if (map != null && !map.get("suggestion").equals("pass")) {
                flag = false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            flag = false;
        }
        //只有满足pass才是通过了审查
        return flag;
    }

    @Override
    public ResponseResult like(CommentRepayLikeDto dto) {
        //1 校验参数是否存在
        if (dto.getCommentRepayId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        //2 从本地线程获取用户信息
        ApUser apUser = ApThreadLocalUtil.getUser();
        if (apUser == null) {
            //未登录或者登录过期了
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        if (apUser.getId() == 0) {
            //游客不让进行用户行为操作
            return ResponseResult.errorResult(AppHttpCodeEnum.VISITOR_NEED_LOGIN);
        }
        //2.1 判断当前评论存在
        ApComment apComment = mongoTemplate.findById(dto.getCommentRepayId(), ApComment.class);
        if (apComment == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //3 查询redis，是否点赞过
        String comment_like_key = "COMMENT_LIKE_" + apUser.getId();
        Boolean flag = stringRedisTemplate.opsForSet().isMember(comment_like_key, dto.getCommentRepayId());
        //4 如果点赞过，并还执行点赞操作，直接返回
        if (flag && dto.getOperation() == 0) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_EXIST);
        }
        //5 点赞过，取消点赞，删除redis数据和mongo中点赞集合，修改mongo中评论集合的点赞数要减一
        if (flag && dto.getOperation() == 1) {
            //删除redis
            stringRedisTemplate.opsForSet().remove(comment_like_key, dto.getCommentRepayId());
            //删除mongo
            Query query = Query.query(Criteria.where("userId").is(apUser.getId())
                    .and("targetId").is(dto.getCommentRepayId()));
            mongoTemplate.remove(query, ApCommentLike.class);
            //修改mongo中评论集合的点赞数要减一
            Query query1 = Query.query(Criteria.where("id").is(apComment.getId())
                    .and("likes").gt(0));
            UpdateDefinition update = new Update().inc("likes", -1);
            mongoTemplate.updateFirst(query1, update, ApComment.class);
        }
        //6 未点赞并执行点赞操作，那么就新增redis数据，新增mongo中点赞集合，修改mongo中评论集合的点赞数要加一
        if (!flag && dto.getOperation() == 0) {
            //新增redis
            stringRedisTemplate.opsForSet().add(comment_like_key, dto.getCommentRepayId());
            //新增mongo中点赞集合
            ApCommentLike apCommentLike = new ApCommentLike();
            apCommentLike.setId(ObjectId.get().toHexString());
            apComment.setUserId(apUser.getId());
            apCommentLike.setTargetId(dto.getCommentRepayId());
            apCommentLike.setCreatedTime(new Date());
            mongoTemplate.insert(apCommentLike);
            //修改mongo中评论集合的点赞数要加一
            Query query = Query.query(Criteria.where("id").is(apComment.getId()));
            UpdateDefinition update = new Update().inc("likes", 1);
            mongoTemplate.updateFirst(query, update, ApComment.class);
        }
        //重新从mongo中查询评论集合中符合条件数据
        apComment = mongoTemplate.findById(dto.getCommentRepayId(), ApComment.class);
        Map<String, Integer> map = new HashMap<>();
        map.put("likes", apComment.getLikes());

        return ResponseResult.okResult(map);
    }

    @Override
    public ResponseResult load(CommentRepayListDto dto) {
        //1 校验参数是否存在
        if (dto.getCommentId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        if (dto.getSize() == null || dto.getSize() == 0) {
            dto.setSize(10);
        }
        //不超过50条数据的就按照给定的数据
        dto.setSize(Math.min(dto.getSize(), 50));
        //根据文章id去查询mongo中的评论表，并进行分页 和排序展示
        Query query = Query.query(Criteria.where("targetId").is(dto.getCommentId())
                .and("createdTime").lt(dto.getMinDate()))//文章时间小于前端给定的时间
                .with(Sort.by(Sort.Direction.DESC, "createdTime"))//排序
                .limit(dto.getSize());//分页
        List<ApComment> apCommentList = mongoTemplate.find(query, ApComment.class);
        if (apCommentList == null || apCommentList.size() <= 0) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //2 从本地线程获取用户信息
        ApUser apUser = ApThreadLocalUtil.getUser();
        if (apUser == null) {
            //未登录或者登录过期了
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        if (apUser.getId() == 0) {
            //游客直接返回评论列表
            return ResponseResult.okResult(apCommentList);
        }
        //3 走到这一步就是用户登录，加载数据的时候，要判断当前用户点赞了哪些评论，并给予标识
        String comment_like_key = "COMMENT_LIKE_" + apUser.getId();
        //根据key查出该用户点赞的所有评论
        Set<String> likeCommentIds = stringRedisTemplate.opsForSet().members(comment_like_key);
        if (likeCommentIds == null) {
            //3.1 没有查到点赞的评论，直接返回评论列表
            return ResponseResult.okResult(apCommentList);
        }
        //3.2 存在点赞的评论，那么就需要添加标记
        List<ApCommentVo> result = apCommentList.stream().map(apComment -> {
            ApCommentVo apCommentVo = new ApCommentVo();
            BeanUtils.copyProperties(apComment, apCommentVo);
            if (likeCommentIds.contains(apComment.getId())) {
                apCommentVo.setOperation((short) 0);
            }
            return apCommentVo;
        }).collect(Collectors.toList());
        //4 返回数据
        return ResponseResult.okResult(result);
    }
}
